#include "IOControlLayer.h"

IOControlLayer::IOControlLayer()
    :disk("./disk.img", std::ios::binary | std::ios::in | std::ios::out)
{
    leisure_chunk = new char[BLOCK_SIZE];
    if (!disk.good()) {
        create_disk_image("./disk.img");
        disk.open("./disk.img", std::ios::binary | std::ios::in | std::ios::out);
    }
    read_disk_image("./disk.img");
    std::cout << "disk.img mount successfully" << std::endl;
}

IOControlLayer::~IOControlLayer(){
    disk.close();
    delete[] leisure_chunk;
}

void IOControlLayer::create_disk_image(const std::string &filename) {
    std::ofstream disk(filename, std::ios::binary | std::ios::trunc);

    Superblock sb = {0xDEADBEEF, BLOCK_SIZE, TOTAL_BLOCKS, 128, TOTAL_BLOCKS - 1 - 128 - 1};
    char block[BLOCK_SIZE] = {0};
    memcpy(block, &sb, sizeof(Superblock));
    disk.write(block, BLOCK_SIZE); // 写入超级块（第0块）

    // 初始化 inode 表（全置零）
    Inode inode = {};
    memcpy(block, &inode, sizeof(Inode));
    for (int i = 0; i < 128; ++i) {
        disk.write(block, BLOCK_SIZE); // 写入 inode 表（第1~128块）
    }

    // 初始化数据块位图（第129块）
    memset(block, 0, BLOCK_SIZE);
    block[0] = 1;
    block[130] = 1;
    block[1] = 1;
    disk.write(block, BLOCK_SIZE); 

    // 填充剩余数据块（可选）
    memset(block, 0, BLOCK_SIZE);
    for (uint32_t i = 130; i < TOTAL_BLOCKS; ++i) {
        disk.write(block, BLOCK_SIZE);
    }

    DirEntry dir = {1, "/\0"};
    memcpy(block, &dir, sizeof(DirEntry));
    disk.seekp(130 * BLOCK_SIZE, std::ios::beg); // 移动写入指针到第130个数据块的位置（根目录）
    disk.write(block, BLOCK_SIZE); // 写入根目录

    inode.size = 1;
    inode.mode = 0x4000; // 目录
    inode.blocks[0] = 130; // 指向第130个数据块（根目录）
    memcpy(block, &inode, sizeof(Inode));
    disk.seekp(1 * BLOCK_SIZE, std::ios::beg); // 移动写入指针到第1个 inode 的位置
    disk.write(block, BLOCK_SIZE); // 写入 inode 表（第1个 inode）


    disk.close();
}

void IOControlLayer::read_disk_image(const std::string &filename){
    if (!disk) {
        std::cerr << "Failed to open disk image file." << std::endl;
        return;
    }
    disk.seekp(0 * BLOCK_SIZE, std::ios::beg);
    char block[BLOCK_SIZE];
    // 读取超级块（第0块）
    disk.read(block, BLOCK_SIZE);
    
    memcpy(&superblock, block, sizeof(Superblock));
    std::cout << "Magic: 0x" << std::hex << superblock.magic << std::dec << std::endl;
    std::cout << "Block size: " << superblock.block_size / 1024 << "kb" << std::endl;
    std::cout << "Total blocks: " << superblock.total_blocks << std::endl;
    std::cout << "Inode count: " << superblock.inode_count << std::endl;
    std::cout << "Free blocks: " << superblock.free_blocks << std::endl;
    std::cout << std::endl;

    Inode inode;
    disk.seekp(2 * BLOCK_SIZE, std::ios::beg);
    // 读取 inode 表（第1~128块）
    for (int i = 1; i <= 128; ++i) {
        disk.seekp((i) * BLOCK_SIZE, std::ios::beg);
        disk.read(block, BLOCK_SIZE);
        memcpy(&inode, block, sizeof(Inode));
        if (inode.mode != 0){
            // std::cout << "Inode " << i << " mode: 0x" << std::hex << inode.mode << std::dec
            //     << " size: " << inode.size << " blocks: " << inode.blocks[0] << std::endl;
            if (inode.mode == 0x8000) continue; // 文件

            DirEntry dir[inode.size];
            disk.seekp(inode.blocks[0] * BLOCK_SIZE, std::ios::beg);
            disk.read(block, BLOCK_SIZE);
            memcpy(dir, block, sizeof(dir));
            std::string parent_path = dir[0].name;
            for (int j = 1; j < inode.size; ++j) {
                // std::cout << "DirEntry " << j << " Inode = " << dir[j].inode << ", Name = " << parent_path + "/" + dir[j].name << std::endl;
                FileTree::GetInstance().insertInitialize(parent_path + "/" + dir[j].name, dir[j].inode);
            }
            // std::cout << std::endl;
        }
    }

    // 读取数据块位图（第129块）
    disk.read(leisure_chunk, BLOCK_SIZE);
    // for (int i = 0; i < TOTAL_BLOCKS - 1 - 128 - 1; ++i){
    //     if (leisure_chunk[i] != 0) {
    //         std::cout << "Block " << i << " is used." << std::endl;
    //     }
    // }

    // // 读取剩余数据块
    // for (uint32_t i = 130; i < TOTAL_BLOCKS; ++i) {
    //     disk.read(block, BLOCK_SIZE);
    // }
}

uint32_t IOControlLayer::leisure_data_chunk(){
    for (uint32_t i = 130; i <= TOTAL_BLOCKS - 1 - 128 - 1; ++i){
        if (leisure_chunk[i] == 0) {
            leisure_chunk[i] = 1;
            return i;
        }
    }
    return 0;
}

uint32_t IOControlLayer::leisure_inode_chunk() {
    for (uint32_t i = 1; i <= 128; ++i){
        if (leisure_chunk[i] == 0) {
            leisure_chunk[i] = 1;
            return i;
        }
    }
    return 0;
}

uint32_t IOControlLayer::create_dir(const std::string &path, uint32_t parent_inode, const std::string &name) {
    uint32_t inode_chunk = leisure_inode_chunk();
    uint32_t data_chunk = leisure_data_chunk();
    char block[BLOCK_SIZE] = {0};

    DirEntry dir[2]{
        {parent_inode, ""},
        {inode_chunk, ""}
    };
    memcpy(dir[1].name, name.c_str(), name.size());
    memcpy(dir[0].name, path.c_str(), path.size());
    memcpy(block, dir, sizeof(dir));
    disk.seekp(data_chunk * BLOCK_SIZE, std::ios::beg);
    disk.write(block, BLOCK_SIZE);

    disk.seekg(data_chunk * BLOCK_SIZE, std::ios::beg);
    DirEntry dird[2];
    disk.read(reinterpret_cast<char*>(dird), sizeof(dir));

    // std::cout << "Read DirEntry 0: Inode = " << dird[0].inode << ", Name = " << dird[0].name << std::endl;
    // std::cout << "Read DirEntry 1: Inode = " << dird[1].inode << ", Name = " << dird[1].name << std::endl;

    Inode inode;
    inode.size = 2;
    inode.mode = 0x4000; // 目录
    inode.blocks[0] = data_chunk; // 指向第130个数据块（根目录）
    memcpy(block, &inode, sizeof(Inode));
    disk.seekp(inode_chunk * BLOCK_SIZE, std::ios::beg); // 移动写入指针到第1个 inode 的位置
    disk.write(block, BLOCK_SIZE); // 写入 inode 表（第1个 inode）

    disk.seekp(129 * BLOCK_SIZE, std::ios::beg);
    disk.write(leisure_chunk, BLOCK_SIZE); 

    return inode_chunk;
}

uint32_t IOControlLayer::create_file(const std::string &path, uint32_t parent_inode, const std::string &name, const std::string &data) {
    uint32_t inode_chunk = leisure_inode_chunk();
    uint32_t data_chunk = leisure_data_chunk();
    // std::cout << "parent_inode: " << parent_inode << std::endl;
    char block[BLOCK_SIZE] = {0};

    Inode fileInode;
    fileInode.size = data.size();
    fileInode.mode = 0x8000; // 文件
    fileInode.blocks[0] = data_chunk; // 指向第130个数据块（根目录）
    memcpy(block, &fileInode, sizeof(Inode));
    disk.seekp(inode_chunk * BLOCK_SIZE, std::ios::beg); // 移动写入指针到第1个 inode 的位置
    disk.write(block, BLOCK_SIZE); // 写入 inode 表（第1个 inode）

    disk.seekp(data_chunk * BLOCK_SIZE, std::ios::beg);
    disk.write(data.c_str(), data.size());
    if (data.size() < BLOCK_SIZE) { // 若数据不足一个块，填充零
        std::vector<char> padding(BLOCK_SIZE - data.size(), 0);
        disk.write(padding.data(), padding.size());
    }

    Inode inode;
    disk.seekp(parent_inode * BLOCK_SIZE, std::ios::beg);
    disk.read(block, BLOCK_SIZE);
    memcpy(&inode, block, sizeof(Inode));
    if (inode.mode != 0){
        inode.size += 1;
        memcpy(block, &inode, sizeof(Inode));
        disk.seekp(parent_inode * BLOCK_SIZE, std::ios::beg);
        disk.write(block, BLOCK_SIZE);

        DirEntry dir[inode.size];
        disk.seekp(inode.blocks[0] * BLOCK_SIZE, std::ios::beg);
        disk.read(block, BLOCK_SIZE);
        memcpy(dir, block, sizeof(dir));
        dir[inode.size - 1].inode = inode_chunk;
        memcpy(dir[inode.size - 1].name, name.c_str(), name.size());
        memcpy(block, dir, sizeof(dir));
        disk.seekp(inode.blocks[0] * BLOCK_SIZE, std::ios::beg);
        disk.write(block, BLOCK_SIZE);

        // disk.seekp(inode.blocks[0] * BLOCK_SIZE, std::ios::beg);
        // disk.read(block, BLOCK_SIZE);
        // for (int i = 0; i < inode.size; ++i) {
        //     std::cout << "DirEntry " << i << " Inode = " << dir[i].inode << ", Name = " << dir[i].name << std::endl;
        // }
    }

    disk.seekp(129 * BLOCK_SIZE, std::ios::beg);
    disk.write(leisure_chunk, BLOCK_SIZE); 

    // disk.seekp(data_chunk * BLOCK_SIZE, std::ios::beg);
    // disk.read(block, BLOCK_SIZE);
    // std::cout << "Data: " << block << std::endl;

    return inode_chunk;
    return 0;
}

std::string IOControlLayer::read_file(uint32_t inodeIdx) {
    // std::cout << "inodeIdx: " << inodeIdx << std::endl;
    char block[BLOCK_SIZE] = {0};

    Inode fileInode;
    disk.seekp(inodeIdx * BLOCK_SIZE, std::ios::beg); // 移动写入指针到第1个 inode 的位置
    disk.read(block, BLOCK_SIZE); // 写入 inode 表（第1个 inode）
    memcpy(&fileInode, block, sizeof(Inode));
    // std::cout << " mode: 0x" << std::hex << fileInode.mode << std::dec
    //     << " size: " << fileInode.size << " blocks: " << fileInode.blocks[0] << std::endl;
    if (fileInode.mode != 0){
        if (fileInode.mode == 0x8000) { // 文件
            std::string data(fileInode.size, '\0');
            disk.seekp(fileInode.blocks[0] * BLOCK_SIZE, std::ios::beg);
            disk.read(data.data(), fileInode.size);
            return data;
        }
    }
    return std::string();
}
